/*
 * AGENT SHERPA
 *  
 * Assignement 2 of the Agent Oriented Software Engineering Course
 * M.Sc. in Advanced Software Engineering (Part-time)
 * University College Dublin www.ucd.ie
 *
 * Copyright (c) 2007 Chris Walsh, Aidan Morrisy and Iain Hull.
 * All rights reserved.
 */

package org.agentsherpa;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.agentsherpa.model.CellType;
import org.agentsherpa.model.Direction;
import org.agentsherpa.model.Drone;
import org.agentsherpa.model.GlobalMap;
import org.agentsherpa.model.Ied;
import org.agentsherpa.model.MapLoadException;
import org.agentsherpa.model.MapProperties;
import org.agentsherpa.model.MapPropertiesException;
import org.agentsherpa.model.MoveException;
import org.agentsherpa.model.Point;
import org.agentsherpa.model.SimulatorModel;
import org.agentsherpa.ui.MapWindow;

import com.agentfactory.platform.interfaces.Agent;
import com.agentfactory.platform.service.PlatformService;
import com.agentfactory.platform.service.PlatformServiceDescriptor;
import com.agentfactory.platform.service.PlatformServiceManager;

/**
 * SimulatorService holds the global map
 */
public class SimulatorService extends PlatformService {
    private Map<String, Drone> drones = new HashMap<String, Drone>();

    private SimulatorModel model;
    private GlobalMap map;
    private MapWindow window;

    private boolean debug = false;

    // Mandatory Platform Service Methods
    public void init(PlatformServiceDescriptor descriptor,
            PlatformServiceManager manager) {

		String file = null;
		for (int i=0; i< descriptor.numberArguments(); ++i) {
			String arg = descriptor.getArgument(i);
			System.out.println(arg);
			if (arg.equalsIgnoreCase("debug")) {
				debug = true;
			}
			else if (arg.equalsIgnoreCase("file")) {
				++i;
				file = descriptor.getArgument(i);
			}
        }

		try {
			if (file != null) {
                MapProperties props = new MapProperties(file);
                
                
				map = new GlobalMap(props.getMapImageFile());
                model = new SimulatorModel(map);
                window = new MapWindow(model, props.getZoom(), props.getBackgroundImageFile());
                window.setVisible(true);
			}
        }
        catch (MapLoadException e) {
            e.printStackTrace();
		}
        catch (MapPropertiesException e) {
            e.printStackTrace();
        }
		debugMessage("Init " + descriptor.getName() + " "
				+ descriptor.getClassName());
    }

    public void start() {
        debugMessage("Started");
    }

    public void bind(Agent agent) {
        debugMessage(agent.getName() + " has joined the service");
        model.addDrone(agent.getName());
    }

    public void unbind(Agent agent) {
        debugMessage(agent.getName() + " has left the service");
        drones.get(agent.getName()).setStatus(Drone.Status.Dead);
    }

    public void modifyBinding(String string, String string0) {
    }

    public void stop() {
        debugMessage("Terminating");
    }

    // Service Specific Methods

    /**
     * Get the Agents current location.
     */
    public synchronized Point getLocation(Agent agent) {
        Drone d = model.getDrone(agent.getName());
        
        if (d != null) {
            Point location = d.getLocation();
            //debugMessage(agent.getName() + " location: " + location);
            return location;
        }
        else {
            //debugMessage(agent.getName() + " location: cannot find agent");
            return Point.BadLocation;
        }
    }

    /**
     * Move the Agent in the specified direction
     * 
     * @param agent
     * @param direction
     */
    public synchronized void move(Agent agent, Direction direction) {
        Drone d = model.getDrone(agent.getName());
        
        if (d != null) {
            try {
                //debugMessage("Moving drone " + d + " " + direction);
                model.move(d, direction);
            }
            catch (MoveException e) {
                debugMessage("Could not move drone " + d + " " + direction);
            }
        }
        else {
            debugMessage("Could not find drone " + agent.getName() + " to move");
        }
    }
    
    public synchronized Point getTargetLocation() {
    	return model.getMap().getTargetLocation();
	}
    
	/**
	 * Get the drone for the specified agent.
	 * @param agent
	 * @return
	 */
    public synchronized Drone getDrone(Agent agent) {
		return model.getDrone(agent.getName());
	}


    /**
     * Get the set of Ieds that the specified Agent can sense from its current
     * location.
     * 
     * @param agent
     * @return
     */
    public synchronized Set<Ied> sensedIeds(Agent agent) {
        return model.sensedIeds(getLocation(agent));
    }

    /**
     * Get the set of Road cells that the specified Agent can sense from its current
     * location.
     * 
     * @param agent
     * @return
     */
    public synchronized Set<Point> senseRoad(Agent agent) {
        return model.senseRoad(getDrone(agent), getLocation(agent));
    }
    
    
	public synchronized Set<Drone> senseDrones(Agent agent) {
		return model.senseDrones(getLocation(agent));
	}

    
   /**
     * Print a debugging message to stdout if we are in debug mode
     * 
     * @param message
     */
    private void debugMessage(String message) {
        if (debug) {
            System.out.print("[SimulatorService] ");
            System.out.println(message);
        }
    }

    public GlobalMap getMap() {
        return map;
    }
    
    public void updateKnownRoad(Map<Point, CellType> update) {
    	model.updateKnownRoad(update);
    }
}
